/** 
 * Copyright (C) 2012 Iordan Iordanov
 * Copyright (C) 2010 Michael A. MacDonald
 * 
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 * USA.
 */

//
// CanvasView is the Activity for showing VNC Desktop.
//
package com.iiordanov.bVNC;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import com.mogujie.tt.R;


import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.media.AudioManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.iiordanov.android.bc.BCFactory;
import com.iiordanov.android.zoomer.ZoomControls;
import com.iiordanov.bVNC.dialogs.EnterTextDialog;
import com.iiordanov.bVNC.dialogs.MetaKeyDialog;
import com.iiordanov.bVNC.input.AbstractInputHandler;
import com.iiordanov.bVNC.input.Panner;
import com.iiordanov.bVNC.input.RemoteKeyboard;
import com.iiordanov.bVNC.input.RemotePointer;
import com.iiordanov.bVNC.input.SimulatedTouchpadInputHandler;
import com.iiordanov.bVNC.input.SingleHandedInputHandler;
import com.iiordanov.bVNC.input.TouchMouseDragPanInputHandler;
import com.iiordanov.bVNC.input.TouchMouseSwipePanInputHandler;
//import com.sxun.launcher.service.ServiceManager;

//cms
import com.iiordanov.bVNC.CmsCtoJava; 
import com.iiordanov.bVNC.CmsControl;
import com.iiordanov.bVNC.dialogs.CmsTextDialog;

//import com.navigation.constant.ConstantCategoryMenu;
//import com.navigation.control.PulldownMenuView;
//import com.navigation.control.PulldownMenuView.OnMenuItemClickListener;
//import com.navigation.utility.MenuUtility;
import com.piemenu.PieControl;

//----
public class RemoteCanvasActivity extends Activity implements OnKeyListener {

	private final static String TAG = "VncCanvasActivity";

	public AbstractInputHandler inputHandler;

	public RemoteCanvas canvas;
	
	// KE15-0120 同步大小写
	boolean firstDetecting = true;
	public Database database;

	private MenuItem[] inputModeMenuItems;
	private MenuItem[] scalingModeMenuItems;
	private AbstractInputHandler inputModeHandlers[];
	public ConnectionBean connection;
	/*
	 * private static final int inputModeIds[] = { R.id.itemInputFitToScreen,
	 * R.id.itemInputTouchpad, R.id.itemInputMouse, R.id.itemInputPan,
	 * R.id.itemInputTouchPanTrackballMouse, R.id.itemInputDPadPanTouchMouse,
	 * R.id.itemInputTouchPanZoomMouse };
	 */
	private static final int inputModeIds[] = { R.id.itemInputTouchpad,
			R.id.itemInputTouchPanZoomMouse, R.id.itemInputDragPanZoomMouse,
			R.id.itemInputSingleHanded };
	private static final int scalingModeIds[] = { R.id.itemZoomable,
			R.id.itemFitToScreen, R.id.itemOneToOne };

	ZoomControls zoomer;
	Panner panner;
	SSHConnection sshConnection;
	Handler handler;

	RelativeLayout layoutKeys;
	ImageButton keyStow;
	ImageButton keyCtrl;
	boolean keyCtrlToggled;
	ImageButton keySuper;
	boolean keySuperToggled;
	ImageButton keyAlt;
	boolean keyAltToggled;
	ImageButton keyTab;
	ImageButton keyEsc;
	ImageButton keyShift;
	boolean keyShiftToggled;
	ImageButton keyUp;
	ImageButton keyDown;
	ImageButton keyLeft;
	ImageButton keyRight;
	
	//cms 
	//	float X;//判断屏幕X
	//	boolean cmsSoftkeyboard =true;
		 public View viewcms; 
			// PulldownMenuView
	//		private MenuUtility menuUtility = null;
			// PulldownMenuView
	//		private PulldownMenuView pullDownMenu = null;
	//		private TextView tvTopic = null;
			
			private FrameLayout mContentView;
			private PieControl mPieControl;
		
			public static RemoteCanvasActivity mRemoteCanvasActivity;
			
			
	//	ImageButton slidingkeyUp;
	//	ImageButton slidingkeyDown;	
		//------
			
	
	boolean hardKeyboardExtended;
	boolean extraKeysHidden = false;
	int prevBottomOffset = 0;
	
	private SpiceCloseReceiver scReceiver;
	
	@Override
	public void onCreate(Bundle icicle) {

		super.onCreate(icicle);
		//cms
		mRemoteCanvasActivity = this;
		// 去除title
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		// 去掉Activity上面的状态栏
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);

		/*Intent intent = this.getIntent();
		String vmid = intent.getStringExtra("fileName");
		String fileName = vmid;
		ServiceManager.myfileName = fileName;
		ServiceManager.mySavePath = getApplicationContext().getFilesDir()
				.toString() + "/ScreenImage";

		System.out.println(ServiceManager.myfileName);*/
		// 对调
		initialize();
		continueConnecting();
		
		scReceiver=new SpiceCloseReceiver();
		IntentFilter filter = new IntentFilter();
		filter.addAction("view.spice.close");
		registerReceiver(scReceiver, filter);
	}

	@Override
	public void onWindowFocusChanged(boolean hasFocus)
    {
		 hideSystemUI(viewcms);
    }
	
	void initialize() {
		if (android.os.Build.VERSION.SDK_INT >= 9) {
			android.os.StrictMode.ThreadPolicy policy = new android.os.StrictMode.ThreadPolicy.Builder()
					.permitAll().build();
			android.os.StrictMode.setThreadPolicy(policy);
		}

		handler = new Handler();

		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);

		database = new Database(this);

		Intent i = getIntent();
		connection = new ConnectionBean(this);

		Uri data = i.getData();

		if ((data != null) && (data.getScheme().equals("vnc"))) {

			// TODO: Can we also handle VNC over SSH/SSL connections with a new
			// URI format?
           
			String host = data.getHost();
			
			// This should not happen according to Uri contract, but bug
			// introduced in Froyo (2.2)
			// has made this parsing of host necessary
			int index = host.indexOf(':');
			int port;
			if (index != -1) {
				try {
					port = Integer.parseInt(host.substring(index + 1));
				} catch (NumberFormatException nfe) {
					port = 0;
				}
				host = host.substring(0, index);
			} else {
				port = data.getPort();
			}
			if (host.equals(Constants.CONNECTION)) {
				if (connection.Gen_read(database.getReadableDatabase(), port)) {
					MostRecentBean bean = bVNC.getMostRecent(database
							.getReadableDatabase());
					if (bean != null) {
						bean.setConnectionId(connection.get_Id());
						bean.Gen_update(database.getWritableDatabase());
						database.close();
					}
				}
			}
			else {
				
				connection.setAddress(host);
				connection.setNickname(connection.getAddress());
				
				connection.setPort(port);
				List<String> path = data.getPathSegments();
				if (path.size() >= 1) {
					connection.setColorModel(path.get(0));
				}
				if (path.size() >= 2) {
					connection.setPassword(path.get(1));
				}
				connection.save(database.getWritableDatabase());
				database.close();
			}
		} else { //data 为空

			Bundle extras = i.getExtras();//得到另一个activity传过来的数值

			if (extras != null) {
				connection.Gen_populate((ContentValues) extras
						.getParcelable(Constants.CONNECTION));
			}
			
			if (connection.getPort() == 0)
				connection.setPort(5900);

			if (connection.getSshPort() == 0)
				connection.setSshPort(22);

			// Parse a HOST:PORT entry
			String host = connection.getAddress();//得到地址
			Log.v("RemoteCanvasActivity","host ="+host);
			if (host.indexOf(':') > -1) 
			{
				String p = host.substring(host.indexOf(':') + 1);
				try {
					Log.v("RemoteCanvasActivity","p ="+p);
					connection.setPort(Integer.parseInt(p));
				} catch (Exception e) {

				}
				Log.v("RemoteCanvasActivity","host.substring(0, host.indexOf(':')) ="+host.substring(0, host.indexOf(':')));
				connection.setAddress(host.substring(0, host.indexOf(':')));
			}
		}
	}

	void continueConnecting() {
		// TODO: Implement left-icon
		// requestWindowFeature(Window.FEATURE_LEFT_ICON);
		// setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
		// R.drawable.icon);
		//cms
		 getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//不锁屏幕
		 //------
		setContentView(R.layout.canvas);
		canvas = (RemoteCanvas) findViewById(R.id.vnc_canvas);
		
		viewcms = getWindow().getDecorView();
		 hideSystemUI(viewcms);
		 
		 zoomer = (ZoomControls) findViewById(R.id.zoomer);
         //cms 扇形菜单
			mContentView = (FrameLayout) findViewById(R.id.main_content);

			if (mPieControl == null)// 这里的原因
			{
				mPieControl = new PieControl(RemoteCanvasActivity.this);
				Log.v("cms_cms", "setUseQuickControls--------------");
				mPieControl.attachToContainer(mContentView);
			}
		 //--------
		// Initialize and define actions for on-screen keys.
		// initializeOnScreenKeys();
		
		//cms
		/*	tvTopic = (TextView) findViewById(R.id.textViewTopic);//图文 用来判断选择按键
			menuUtility = new MenuUtility(
	    			RemoteCanvasActivity.this, 
	    			ConstantCategoryMenu.newsImageRes,//图标资源
	    			ConstantCategoryMenu.newsMenuTexts//设置图标的名称
	    		     );
	    	showPulldownMenu();*/
	    	//------
	    	
		canvas.initializeCanvas(connection, database, new Runnable() {
			public void run() {
				try {
					setModes();
				} catch (NullPointerException e) {

				}
			}
		});
		
		canvas.setOnKeyListener(this);
		canvas.setFocusableInTouchMode(true);
		canvas.setDrawingCacheEnabled(false);
		
		/*canvas.setOnLongClickListener(new View.OnLongClickListener() {
			@Override
			public boolean onLongClick(View arg0) {
				Toast.makeText(getApplicationContext(), "sssssss", 1).show();
				return false;
			}
		});*/
		
		// This code detects when the soft keyboard is up and sets an
		// appropriate visibleHeight in vncCanvas.
		// When the keyboard is gone, it resets visibleHeight and pans zero
		// distance to prevent us from being
		// below the desktop image (if we scrolled all the way down when the
		// keyboard was up).
		// TODO: Move this into a separate thread, and post the visibility
		// changes to the handler.
		// to avoid occupying the UI thread with this.
		final View rootView = ((ViewGroup) findViewById(android.R.id.content))
				.getChildAt(0);
		rootView.getViewTreeObserver().addOnGlobalLayoutListener(
				new OnGlobalLayoutListener() {
					@Override
					public void onGlobalLayout() {
						Rect r = new Rect();

						rootView.getWindowVisibleDisplayFrame(r);

						// To avoid setting the visible height to a wrong value
						// after an screen unlock event
						// (when r.bottom holds the width of the screen rather
						// than the height due to a rotation)
						// we make sure r.top is zero (i.e. there is no
						// notification bar and we are in full-screen mode)
						// It's a bit of a hack.
						if (r.top == 0) {
							if (canvas.bitmapData != null) {
								canvas.setVisibleHeight(r.bottom);
								canvas.pan(0, 0);
							}
						}

						// Enable/show the zoomer if the keyboard is gone, and
						// disable/hide otherwise.
						// We detect the keyboard if more than 19% of the screen
						// is covered.
						int offset = 0;
						int rootViewHeight = rootView.getHeight();
						if (r.bottom > rootViewHeight * 0.81) {
							offset = rootViewHeight - r.bottom;
							// Soft Kbd gone, shift the meta keys and arrows
							// down.
							// KE060514
							/*
							 * if (layoutKeys != null) {
							 * layoutKeys.offsetTopAndBottom(offset);
							 * keyStow.offsetTopAndBottom(offset); if
							 * (prevBottomOffset != offset) {
							 * setExtraKeysVisibility(View.GONE, false);
							 * canvas.invalidate(); zoomer.enable(); } } } else
							 * { offset = r.bottom - rootViewHeight; // Soft Kbd
							 * up, shift the meta keys and arrows up. if
							 * (layoutKeys != null) {
							 * layoutKeys.offsetTopAndBottom(offset);
							 * keyStow.offsetTopAndBottom(offset); if
							 * (prevBottomOffset != offset) {
							 * setExtraKeysVisibility(View.VISIBLE, true);
							 * canvas.invalidate(); zoomer.hide();
							 * zoomer.disable(); } }
							 */
							//cms
							canvas.invalidate(); zoomer.enable();
						}
						setKeyStowDrawableAndVisibility();
						prevBottomOffset = offset;
					}
				});

		// KE062414
		// zoomer.hide();
		// zoomer.setOnZoomKeyboardClickListener(new View.OnClickListener() {

		/*
		 * (non-Javadoc)
		 * 
		 * @see android.view.View.OnClickListener#onClick(android.view.View)
		 */
		/*
		 * @Override public void onClick(View v) { InputMethodManager inputMgr =
		 * (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
		 * inputMgr.toggleSoftInput(0, 0);
		 * 
		 * }
		 * 
		 * });
		 */

		// KE 2014-12-19 function is Voice control
		AudioManager mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
		canvas.sxunSetAudioManager(mAudioManager);
		panner = new Panner(this, canvas.handler);
		inputHandler = getInputHandlerById(R.id.itemInputTouchPanZoomMouse);
		
	}
   //cms
	/* protected void showPulldownMenu(){
	    	pullDownMenu = menuUtility.getPulldownMenuView((String)tvTopic.getText());//构造弹窗设置
	    }
	
	 protected void hidePulldownMenu(){
	    	pullDownMenu.releasePopupMenuView();
	   
	    }*/
	 //------
	private void setKeyStowDrawableAndVisibility() {
		// KE060514
		/*
		 * Drawable replacer = null; if (layoutKeys.getVisibility() ==
		 * View.GONE) replacer =
		 * getResources().getDrawable(R.drawable.showkeys); else replacer =
		 * getResources().getDrawable(R.drawable.hidekeys);
		 * keyStow.setBackgroundDrawable(replacer);
		 * 
		 * if (connection.getExtraKeysToggleType() == Constants.EXTRA_KEYS_OFF)
		 * keyStow.setVisibility(View.GONE); else
		 * keyStow.setVisibility(View.VISIBLE);
		 */
	}
    
	
	//cms
	/*
	private void cmsinitOnScreenKeys()
	{
		
		slidingkeyUp = (ImageButton) findViewById(R.id.keyUpArrow);
		slidingkeyUp.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
			Log.v("","00000000000000000000000");	
			
			}
		});

		slidingkeyDown = (ImageButton) findViewById(R.id.keyDownArrow);
		slidingkeyDown.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				Log.v("","111111111111111111111111111111111");
				 
			
			}
		});
	}
	*/
	
	/**
	 * Initializes the on-screen keys for meta keys and arrow keys.
	 */
	private void initializeOnScreenKeys() {
/*
		layoutKeys = (RelativeLayout) findViewById(R.id.layoutKeys);

		// KE060514
		*//*
		 * keyStow = (ImageButton) findViewById(R.id.keyStow);
		 * setKeyStowDrawableAndVisibility(); keyStow.setOnClickListener(new
		 * OnClickListener () {
		 * 
		 * @Override public void onClick(View arg0) { if
		 * (layoutKeys.getVisibility() == View.VISIBLE) { extraKeysHidden =
		 * true; setExtraKeysVisibility(View.GONE, false); } else {
		 * extraKeysHidden = false; setExtraKeysVisibility(View.VISIBLE, true);
		 * } layoutKeys.offsetTopAndBottom(prevBottomOffset);
		 * setKeyStowDrawableAndVisibility(); } });
		 *//*

		// Define action of tab key and meta keys.
		keyTab = (ImageButton) findViewById(R.id.keyTab);
		keyTab.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View arg0, MotionEvent e) {
				RemoteKeyboard k = canvas.getKeyboard();
				int key = KeyEvent.KEYCODE_TAB;
				if (e.getAction() == MotionEvent.ACTION_DOWN) {
					// KE061114
					// BCFactory.getInstance().getBCHaptic().performLongPressHaptic(canvas);
					// keyTab.setImageResource(R.drawable.tabon);
					// k.repeatKeyEvent(key, new KeyEvent(e.getAction(), key));
					return true;
				} else if (e.getAction() == MotionEvent.ACTION_UP) {
					// KE061114
					// keyTab.setImageResource(R.drawable.taboff);
					// resetOnScreenKeys (0);
					// k.stopRepeatingKeyEvent();
					return true;
				}
				return false;
			}
		});

		keyEsc = (ImageButton) findViewById(R.id.keyEsc);
		keyEsc.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View arg0, MotionEvent e) {
				RemoteKeyboard k = canvas.getKeyboard();
				int key = 111; *//* KEYCODE_ESCAPE *//*
				if (e.getAction() == MotionEvent.ACTION_DOWN) {
					BCFactory.getInstance().getBCHaptic()
							.performLongPressHaptic(canvas);
					keyEsc.setImageResource(R.drawable.escon);
					k.repeatKeyEvent(key, new KeyEvent(e.getAction(), key));
					return true;
				} else if (e.getAction() == MotionEvent.ACTION_UP) {
					keyEsc.setImageResource(R.drawable.escoff);
					resetOnScreenKeys(0);
					k.stopRepeatingKeyEvent();
					return true;
				}
				return false;
			}
		});

		keyCtrl = (ImageButton) findViewById(R.id.keyCtrl);
		keyCtrl.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				boolean on = canvas.getKeyboard().onScreenCtrlToggle();
				keyCtrlToggled = false;
				if (on)
					keyCtrl.setImageResource(R.drawable.ctrlon);
				else
					keyCtrl.setImageResource(R.drawable.ctrloff);
			}
		});

		keyCtrl.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View arg0) {
				BCFactory.getInstance().getBCHaptic()
						.performLongPressHaptic(canvas);
				boolean on = canvas.getKeyboard().onScreenCtrlToggle();
				keyCtrlToggled = true;
				if (on)
					keyCtrl.setImageResource(R.drawable.ctrlon);
				else
					keyCtrl.setImageResource(R.drawable.ctrloff);
				return true;
			}
		});

		keySuper = (ImageButton) findViewById(R.id.keySuper);
		keySuper.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				boolean on = canvas.getKeyboard().onScreenSuperToggle();
				keySuperToggled = false;
				if (on)
					keySuper.setImageResource(R.drawable.superon);
				else
					keySuper.setImageResource(R.drawable.superoff);
			}
		});

		keySuper.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View arg0) {
				BCFactory.getInstance().getBCHaptic()
						.performLongPressHaptic(canvas);
				boolean on = canvas.getKeyboard().onScreenSuperToggle();
				keySuperToggled = true;
				if (on)
					keySuper.setImageResource(R.drawable.superon);
				else
					keySuper.setImageResource(R.drawable.superoff);
				return true;
			}
		});

		keyAlt = (ImageButton) findViewById(R.id.keyAlt);
		keyAlt.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				boolean on = canvas.getKeyboard().onScreenAltToggle();
				keyAltToggled = false;
				if (on)
					keyAlt.setImageResource(R.drawable.alton);
				else
					keyAlt.setImageResource(R.drawable.altoff);
			}
		});

		keyAlt.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View arg0) {
				BCFactory.getInstance().getBCHaptic()
						.performLongPressHaptic(canvas);
				boolean on = canvas.getKeyboard().onScreenAltToggle();
				keyAltToggled = true;
				if (on)
					keyAlt.setImageResource(R.drawable.alton);
				else
					keyAlt.setImageResource(R.drawable.altoff);
				return true;
			}
		});

		keyShift = (ImageButton) findViewById(R.id.keyShift);
		keyShift.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				boolean on = canvas.getKeyboard().onScreenShiftToggle();
				keyShiftToggled = false;
				if (on)
					keyShift.setImageResource(R.drawable.shifton);
				else
					keyShift.setImageResource(R.drawable.shiftoff);
			}
		});

		keyShift.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View arg0) {
				BCFactory.getInstance().getBCHaptic()
						.performLongPressHaptic(canvas);
				boolean on = canvas.getKeyboard().onScreenShiftToggle();
				keyShiftToggled = true;
				if (on)
					keyShift.setImageResource(R.drawable.shifton);
				else
					keyShift.setImageResource(R.drawable.shiftoff);
				return true;
			}
		});

		// TODO: Evaluate whether I should instead be using:
		// vncCanvas.sendMetaKey(MetaKeyBean.keyArrowLeft);

		// Define action of arrow keys.
		keyUp = (ImageButton) findViewById(R.id.keyUpArrow);
		keyUp.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View arg0, MotionEvent e) {
				RemoteKeyboard k = canvas.getKeyboard();
				int key = KeyEvent.KEYCODE_DPAD_UP;
				if (e.getAction() == MotionEvent.ACTION_DOWN) {
					BCFactory.getInstance().getBCHaptic()
							.performLongPressHaptic(canvas);
					keyUp.setImageResource(R.drawable.upon);
					k.repeatKeyEvent(key, new KeyEvent(e.getAction(), key));
					return true;
				} else if (e.getAction() == MotionEvent.ACTION_UP) {
					keyUp.setImageResource(R.drawable.upoff);
					resetOnScreenKeys(0);
					k.stopRepeatingKeyEvent();
					return true;
				}
				return false;
			}
		});

		keyDown = (ImageButton) findViewById(R.id.keyDownArrow);
		keyDown.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View arg0, MotionEvent e) {
				RemoteKeyboard k = canvas.getKeyboard();
				int key = KeyEvent.KEYCODE_DPAD_DOWN;
				if (e.getAction() == MotionEvent.ACTION_DOWN) {
					BCFactory.getInstance().getBCHaptic()
							.performLongPressHaptic(canvas);
					keyDown.setImageResource(R.drawable.downon);
					k.repeatKeyEvent(key, new KeyEvent(e.getAction(), key));
					return true;
				} else if (e.getAction() == MotionEvent.ACTION_UP) {
					keyDown.setImageResource(R.drawable.downoff);
					resetOnScreenKeys(0);
					k.stopRepeatingKeyEvent();
					return true;
				}
				return false;
			}
		});

		keyLeft = (ImageButton) findViewById(R.id.keyLeftArrow);
		keyLeft.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View arg0, MotionEvent e) {
				RemoteKeyboard k = canvas.getKeyboard();
				int key = KeyEvent.KEYCODE_DPAD_LEFT;
				if (e.getAction() == MotionEvent.ACTION_DOWN) {
					BCFactory.getInstance().getBCHaptic()
							.performLongPressHaptic(canvas);
					keyLeft.setImageResource(R.drawable.lefton);
					k.repeatKeyEvent(key, new KeyEvent(e.getAction(), key));
					return true;
				} else if (e.getAction() == MotionEvent.ACTION_UP) {
					keyLeft.setImageResource(R.drawable.leftoff);
					resetOnScreenKeys(0);
					k.stopRepeatingKeyEvent();
					return true;
				}
				return false;
			}
		});

		keyRight = (ImageButton) findViewById(R.id.keyRightArrow);
		keyRight.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View arg0, MotionEvent e) {
				RemoteKeyboard k = canvas.getKeyboard();
				int key = KeyEvent.KEYCODE_DPAD_RIGHT;
				if (e.getAction() == MotionEvent.ACTION_DOWN) {
					BCFactory.getInstance().getBCHaptic()
							.performLongPressHaptic(canvas);
					keyRight.setImageResource(R.drawable.righton);
					k.repeatKeyEvent(key, new KeyEvent(e.getAction(), key));
					return true;
				} else if (e.getAction() == MotionEvent.ACTION_UP) {
					keyRight.setImageResource(R.drawable.rightoff);
					resetOnScreenKeys(0);
					k.stopRepeatingKeyEvent();
					return true;
				}
				return false;
			}
		});*/
	}

	/**
	 * Resets the state and image of the on-screen keys.
	 */
	private void resetOnScreenKeys(int keyCode) {
		// Do not reset on-screen keys if keycode is SHIFT.
		switch (keyCode) {
		case KeyEvent.KEYCODE_SHIFT_LEFT:
		case KeyEvent.KEYCODE_SHIFT_RIGHT:
			return;
		}
		if (!keyCtrlToggled) {
			keyCtrl.setImageResource(R.drawable.ctrloff);
			canvas.getKeyboard().onScreenCtrlOff();
		}
		if (!keyAltToggled) {
			keyAlt.setImageResource(R.drawable.altoff);
			canvas.getKeyboard().onScreenAltOff();
		}
		if (!keySuperToggled) {
			keySuper.setImageResource(R.drawable.superoff);
			canvas.getKeyboard().onScreenSuperOff();
		}
		if (!keyShiftToggled) {
			keyShift.setImageResource(R.drawable.shiftoff);
			canvas.getKeyboard().onScreenShiftOff();
		}
	}

	/**
	 * Sets the visibility of the extra keys appropriately.
	 */
	private void setExtraKeysVisibility(int visibility, boolean forceVisible) {
		Configuration config = getResources().getConfiguration();
		// Log.e(TAG, "Hardware kbd hidden: " +
		// Integer.toString(config.hardKeyboardHidden));
		// Log.e(TAG, "Any keyboard hidden: " +
		// Integer.toString(config.keyboardHidden));
		// Log.e(TAG, "Keyboard type: " + Integer.toString(config.keyboard));

		boolean makeVisible = forceVisible;
		if (config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO)
			makeVisible = true;

		if (!extraKeysHidden
				&& makeVisible
				&& connection.getExtraKeysToggleType() == Constants.EXTRA_KEYS_ON) {
			layoutKeys.setVisibility(View.VISIBLE);
			layoutKeys.invalidate();
			return;
		}

		if (visibility == View.GONE) {
			layoutKeys.setVisibility(View.GONE);
			layoutKeys.invalidate();
		}
	}

	/*
	 * TODO: REMOVE THIS AS SOON AS POSSIBLE. onPause: This is an ugly hack for
	 * the Playbook, because the Playbook hides the keyboard upon unlock. This
	 * causes the visible height to remain less, as if the soft keyboard is
	 * still up. This hack must go away as soon as the Playbook doesn't need it
	 * anymore.
	 */
	@Override
	protected void onPause() {
		super.onPause();
		try {
			InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
			imm.hideSoftInputFromWindow(canvas.getWindowToken(), 0);
		} catch (NullPointerException e) {

		}
	}

	/*
	 * TODO: REMOVE THIS AS SOON AS POSSIBLE. onResume: This is an ugly hack for
	 * the Playbook which hides the keyboard upon unlock. This causes the
	 * visible height to remain less, as if the soft keyboard is still up. This
	 * hack must go away as soon as the Playbook doesn't need it anymore.
	 */
	@Override
	protected void onResume() {
		super.onResume();
		Log.i(TAG, "onResume called.");
		try {
			canvas.postInvalidateDelayed(600);
		} catch (NullPointerException e) {

		}
	}

	/**
	 * Set modes on start to match what is specified in the ConnectionBean;
	 * color mode (already done) scaling, input mode
	 */
	void setModes() {
		AbstractInputHandler handler = getInputHandlerByName(connection
				.getInputMode());
		AbstractScaling.getByScaleType(connection.getScaleMode())
				.setScaleTypeForActivity(this);//缩放
		this.inputHandler = handler;
		showPanningState(false);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onCreateDialog(int)
	 */
	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case R.layout.entertext:
			return new EnterTextDialog(this);
		case R.id.itemHelpInputMode:
			return createHelpDialog();
		}

		// Default to meta key dialog
		return new MetaKeyDialog(this);
	}

	/**
	 * Creates the help dialog for this activity.
	 */
	private Dialog createHelpDialog() {
		AlertDialog.Builder adb = new AlertDialog.Builder(this).setMessage(
				R.string.input_mode_help_text).setPositiveButton(
				R.string.close, new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int whichButton) {
						// We don't have to do anything.
					}
				});
		Dialog d = adb.setView(new ListView(this)).create();
		WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
		lp.copyFrom(d.getWindow().getAttributes());
		lp.width = WindowManager.LayoutParams.FILL_PARENT;
		lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
		d.show();
		d.getWindow().setAttributes(lp);
		return d;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onPrepareDialog(int, android.app.Dialog)
	 */
	@Override
	protected void onPrepareDialog(int id, Dialog dialog) {
		super.onPrepareDialog(id, dialog);
		if (dialog instanceof ConnectionSettable)
			((ConnectionSettable) dialog).setConnection(connection);
	}

	/**
	 * This runnable fixes things up after a rotation.
	 */
	private Runnable rotationCorrector = new Runnable() {
		public void run() {
			try {
				correctAfterRotation();
			} catch (NullPointerException e) {

			}
		}
	};

	/**
	 * This function is called by the rotationCorrector runnable to fix things
	 * up after a rotation.
	 */
	private void correctAfterRotation() {
		// Its quite common to see NullPointerExceptions here when this function
		// is called
		// at the point of disconnection. Hence, we catch and ignore the error.
		float oldScale = canvas.scaling.getScale();
		int x = canvas.absoluteXPosition;
		int y = canvas.absoluteYPosition;
		canvas.scaling.setScaleTypeForActivity(RemoteCanvasActivity.this);//缩放
		float newScale = canvas.scaling.getScale();
		canvas.scaling.adjust(this, oldScale / newScale, 0, 0);
		newScale = canvas.scaling.getScale();
		if (newScale <= oldScale) {
			canvas.absoluteXPosition = x;
			canvas.absoluteYPosition = y;
			canvas.scrollToAbsolute();
		}
	}

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);

		try {
			setExtraKeysVisibility(View.GONE, false);

			// Correct a few times just in case. There is no visual effect.
			handler.postDelayed(rotationCorrector, 300);
			handler.postDelayed(rotationCorrector, 600);
			handler.postDelayed(rotationCorrector, 1200);
		} catch (NullPointerException e) {

		}
	}

	@Override
	protected void onStart() {
		super.onStart();
		try {
			canvas.postInvalidateDelayed(800);
		} catch (NullPointerException e) {

		}
	}

	@Override
	protected void onStop() {
		super.onStop();
	}

	@Override
	protected void onRestart() {
		super.onRestart();
		try {
			canvas.postInvalidateDelayed(1000);
		} catch (NullPointerException e) {

		}
	}

	
	/** {@inheritDoc} */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		//cms
		 Log.v(TAG,"RemoteCanvasActivity onCreateOptionsMenu");
		//-----
		try {
			getMenuInflater().inflate(R.menu.vnccanvasactivitymenu, menu);//得到menu里面的VNC的菜单键列表

			menu.findItem(canvas.scaling.getId()).setChecked(true);

			Menu inputMenu = menu.findItem(R.id.itemInputMode).getSubMenu();
			inputModeMenuItems = new MenuItem[inputModeIds.length];
			for (int i = 0; i < inputModeIds.length; i++) {
				inputModeMenuItems[i] = inputMenu.findItem(inputModeIds[i]);
			}
			updateInputMenu();

			Menu scalingMenu = menu.findItem(R.id.itemScaling).getSubMenu();
			scalingModeMenuItems = new MenuItem[scalingModeIds.length];
			for (int i = 0; i < scalingModeIds.length; i++) {
				scalingModeMenuItems[i] = scalingMenu
						.findItem(scalingModeIds[i]);
			}
			updateScalingMenu();

			// Set the text of the Extra Keys menu item appropriately.
			if (connection.getExtraKeysToggleType() == Constants.EXTRA_KEYS_ON)
				menu.findItem(R.id.itemExtraKeys).setTitle(
						R.string.extra_keys_disable);
			else
				menu.findItem(R.id.itemExtraKeys).setTitle(
						R.string.extra_keys_enable);

			/*
			 * menu.findItem(R.id.itemFollowMouse).setChecked(
			 * connection.getFollowMouse());
			 * menu.findItem(R.id.itemFollowPan).setChecked
			 * (connection.getFollowPan());
			 */
			/*
			 * TODO: This is how one detects long-presses on menu items.
			 * However, getActionView is not available in Android 2.3...
			 * menu.findItem
			 * (R.id.itemExtraKeys).getActionView().setOnLongClickListener(new
			 * OnLongClickListener () {
			 * 
			 * @Override public boolean onLongClick(View arg0) {
			 * Toast.makeText(arg0.getContext(), "Long Press Detected.",
			 * Toast.LENGTH_LONG).show(); return false; }
			 * 
			 * });
			 */
		} catch (NullPointerException e) {
		}
		return true;
	}
	
	/**
	 * Change the scaling mode sub-menu to reflect available scaling modes.
	 */
	void updateScalingMenu() {
		try {
			for (MenuItem item : scalingModeMenuItems) {
				// If the entire framebuffer is NOT contained in the bitmap,
				// fit-to-screen is meaningless.
				if (item.getItemId() == R.id.itemFitToScreen) {
					if (canvas != null
							&& canvas.bitmapData != null
							&& (canvas.bitmapData.bitmapheight != canvas.bitmapData.framebufferheight || canvas.bitmapData.bitmapwidth != canvas.bitmapData.framebufferwidth))
						item.setEnabled(false);
					else
						item.setEnabled(true);
				} else
					item.setEnabled(true);
			}
		} catch (NullPointerException e) {

		}
	}

	/**
	 * Change the input mode sub-menu to reflect change in scaling
	 */
	void updateInputMenu() {
		try {
			for (MenuItem item : inputModeMenuItems) {
				item.setEnabled(canvas.scaling.isValidInputMode(item
						.getItemId()));
				if (getInputHandlerById(item.getItemId()) == inputHandler)
					item.setChecked(true);
			}
		} catch (NullPointerException e) {

		}
	}

	/**
	 * If id represents an input handler, return that; otherwise return null
	 * 
	 * @param id
	 * @return
	 */
	AbstractInputHandler getInputHandlerById(int id) {
		boolean isRdp = getPackageName().contains("RDP");

		if (inputModeHandlers == null) {
			inputModeHandlers = new AbstractInputHandler[inputModeIds.length];
		}
		for (int i = 0; i < inputModeIds.length; ++i) {
			if (inputModeIds[i] == id) {
				if (inputModeHandlers[i] == null) {
					switch (id) {
					/*
					 * case R.id.itemInputFitToScreen: inputModeHandlers[i] =
					 * new FitToScreenMode(); break; case R.id.itemInputPan:
					 * inputModeHandlers[i] = new PanMode(); break; case
					 * R.id.itemInputTouchPanTrackballMouse:
					 * inputModeHandlers[i] = new TouchPanTrackballMouse();
					 * break; case R.id.itemInputMouse: inputModeHandlers[i] =
					 * new MouseMode(); break;
					 * 
					 * case R.id.itemInputDPadPanTouchMouse:
					 * inputModeHandlers[i] = new DPadPanTouchMouseMode();
					 * break;
					 */
					case R.id.itemInputTouchPanZoomMouse:
						Log.v("","TouchMouseSwipePanInputHandler");
						inputModeHandlers[i] = new TouchMouseSwipePanInputHandler(
								this, canvas, isRdp);
						break;
					case R.id.itemInputDragPanZoomMouse:
						Log.v("","TouchMouseDragPanInputHandler");
						inputModeHandlers[i] = new TouchMouseDragPanInputHandler(
								this, canvas, isRdp);
						break;
					case R.id.itemInputTouchpad:
						Log.v("","SimulatedTouchpadInputHandler");
						inputModeHandlers[i] = new SimulatedTouchpadInputHandler(
								this, canvas, isRdp);
						break;
					case R.id.itemInputSingleHanded:
						Log.v("","SingleHandedInputHandler");
						inputModeHandlers[i] = new SingleHandedInputHandler(
								this, canvas, isRdp);
						break;

					}
				}
				return inputModeHandlers[i];
			}
		}
		return null;
	}

	void clearInputHandlers() {
		if (inputModeHandlers == null)
			return;

		for (int i = 0; i < inputModeIds.length; ++i) {
			inputModeHandlers[i] = null;
		}
		inputModeHandlers = null;
	}

	AbstractInputHandler getInputHandlerByName(String name) {
		AbstractInputHandler result = null;
		for (int id : inputModeIds) {
			AbstractInputHandler handler = getInputHandlerById(id);
			if (handler.getName().equals(name)) {
				result = handler;
				break;
			}
		}
		if (result == null) {
			result = getInputHandlerById(R.id.itemInputTouchPanZoomMouse);
		}
		return result;
	}

	int getModeIdFromHandler(AbstractInputHandler handler) {
		for (int id : inputModeIds) {
			if (handler == getInputHandlerById(id))
				return id;
		}
		return R.id.itemInputTouchPanZoomMouse;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		canvas.getKeyboard().setAfterMenu(true);
		switch (item.getItemId()) {
		case R.id.itemInfo:
			// KE061314
			canvas.showConnectionInfo();
			return true;
		case R.id.itemSpecialKeys:
			showDialog(R.layout.metakey);
			return true;
		case R.id.itemColorMode:
			selectColorModel();//设置颜色模式
			return true;
			// Following sets one of the scaling options
		case R.id.itemZoomable:
		case R.id.itemOneToOne:
		case R.id.itemFitToScreen:
			AbstractScaling.getById(item.getItemId()).setScaleTypeForActivity(
					this);
			item.setChecked(true);
			showPanningState(false);//设置屏幕缩放
			return true;
		case R.id.itemCenterMouse: //鼠标模式
			canvas.getPointer().warpMouse(
					canvas.absoluteXPosition + canvas.getVisibleWidth() / 2,
					canvas.absoluteYPosition + canvas.getVisibleHeight() / 2);
			return true;
		case R.id.itemDisconnect:
			canvas.closeConnection();//关闭云桌面
			finish();
			return true;
		case R.id.itemEnterText:
			showDialog(R.layout.entertext);
			return true;
		case R.id.itemCtrlAltDel:
			canvas.getKeyboard().sendMetaKey(MetaKeyBean.keyCtrlAltDel);
			return true;
			/*
			 * case R.id.itemFollowMouse: boolean newFollow =
			 * !connection.getFollowMouse(); item.setChecked(newFollow);
			 * connection.setFollowMouse(newFollow); if (newFollow) {
			 * vncCanvas.panToMouse(); }
			 * connection.save(database.getWritableDatabase());
			 * database.close(); return true; case R.id.itemFollowPan: boolean
			 * newFollowPan = !connection.getFollowPan();
			 * item.setChecked(newFollowPan);
			 * connection.setFollowPan(newFollowPan);
			 * connection.save(database.getWritableDatabase());
			 * database.close(); return true;
			 * 
			 * case R.id.itemArrowLeft:
			 * vncCanvas.sendMetaKey(MetaKeyBean.keyArrowLeft); return true;
			 * case R.id.itemArrowUp:
			 * vncCanvas.sendMetaKey(MetaKeyBean.keyArrowUp); return true; case
			 * R.id.itemArrowRight:
			 * vncCanvas.sendMetaKey(MetaKeyBean.keyArrowRight); return true;
			 * case R.id.itemArrowDown:
			 * vncCanvas.sendMetaKey(MetaKeyBean.keyArrowDown); return true;
			 */
		case R.id.itemSendKeyAgain:
			sendSpecialKeyAgain();
			return true;
			// Disabling Manual/Wiki Menu item as the original does not
			// correspond to this project anymore.
			// case R.id.itemOpenDoc:
			// Utils.showDocumentation(this);
			// return true;
		case R.id.itemExtraKeys:
			if (connection.getExtraKeysToggleType() == Constants.EXTRA_KEYS_ON) {
				connection.setExtraKeysToggleType(Constants.EXTRA_KEYS_OFF);
				item.setTitle(R.string.extra_keys_enable);
				setExtraKeysVisibility(View.GONE, false);
			} else {
				connection.setExtraKeysToggleType(Constants.EXTRA_KEYS_ON);
				item.setTitle(R.string.extra_keys_disable);
				setExtraKeysVisibility(View.VISIBLE, false);
				extraKeysHidden = false;
			}
			setKeyStowDrawableAndVisibility();
			connection.save(database.getWritableDatabase());
			database.close();
			return true;
		case R.id.itemHelpInputMode:
			//cms 显示说明帮助会话框
			showDialog(R.id.itemHelpInputMode);
			return true;
		default:
			//cms
			Log.v("","AbstractInputHandler input = getInputHandlerById(item.getItemId())");
			AbstractInputHandler input = getInputHandlerById(item.getItemId());//没有选择时
			if (input != null) {
				inputHandler = input;
				connection.setInputMode(input.getName());
				if (input.getName().equals(
						SimulatedTouchpadInputHandler.TOUCHPAD_MODE)) {
					connection.setFollowMouse(true);
					connection.setFollowPan(true);
				} else {
					connection.setFollowMouse(false);
					connection.setFollowPan(false);
				}

				item.setChecked(true);
				showPanningState(true);
				connection.save(database.getWritableDatabase());
				database.close();
				return true;
			}
		}
		return super.onOptionsItemSelected(item);
	}
	
	//cms
		class PageTask extends AsyncTask<String, Integer, String> {

			 Dialog dialog;
	         @Override
	         protected void onPreExecute() {
	           
	        	 dialog = new CmsTextDialog(RemoteCanvasActivity.this);
		         dialog.show();  	
		       
	         }

			@Override
			protected String doInBackground(String... params) {
				// TODO Auto-generated method stub
					
				return null;
			}
			
			 @Override
		        protected void onPostExecute(String result) {	           
				  try {
						Thread.sleep(100);
						dialog.dismiss();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
		        }
		}		
		//---------
		
	private MetaKeyBean lastSentKey;

	private void sendSpecialKeyAgain() {
		if (lastSentKey == null
				|| lastSentKey.get_Id() != connection.getLastMetaKeyId()) {
			ArrayList<MetaKeyBean> keys = new ArrayList<MetaKeyBean>();
			Cursor c = database.getReadableDatabase().rawQuery(
					MessageFormat.format("SELECT * FROM {0} WHERE {1} = {2}",
							MetaKeyBean.GEN_TABLE_NAME,
							MetaKeyBean.GEN_FIELD__ID,
							connection.getLastMetaKeyId()),
					MetaKeyDialog.EMPTY_ARGS);
			MetaKeyBean.Gen_populateFromCursor(c, keys, MetaKeyBean.NEW);
			c.close();
			if (keys.size() > 0) {
				lastSentKey = keys.get(0);
			} else {
				lastSentKey = null;
			}
		}
		if (lastSentKey != null)
			canvas.getKeyboard().sendMetaKey(lastSentKey);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		
		unregisterReceiver(scReceiver);
		
		if (canvas != null)
			canvas.closeConnection();
		if (database != null)
			database.close();
		canvas = null;
		connection = null;
		database = null;
		zoomer = null;
		panner = null;
		clearInputHandlers();
		inputHandler = null;
		System.gc();
	}

	boolean aIsDown = false;
	boolean qIsDown = false;
	boolean f11IsDown = false;
	boolean copyMode = false;

	@Override
	public boolean dispatchKeyEvent(KeyEvent event) {
		// TODO Auto-generated method stub
		// KE15-0120 同步大小写
		if (true == firstDetecting && true == event.isCapsLockOn()) {
			// cms
			CmsCtoJava.setCapslockonsignal(event.isCapsLockOn());

		}
		firstDetecting = false;
		// 判断普通按键
		int keyCode = event.getKeyCode();
		if ((keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)
				&& event.getAction() == KeyEvent.ACTION_DOWN) {
			aIsDown = true;
		} else if (keyCode == KeyEvent.KEYCODE_F12
				&& event.getAction() == KeyEvent.ACTION_DOWN) {
			qIsDown = true;
		} else if ((keyCode == KeyEvent.KEYCODE_F12 && !aIsDown)
				|| ((keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) && !qIsDown)) {
			aIsDown = false;
			qIsDown = false;
		} else if (aIsDown
				&& qIsDown
				&& (keyCode == KeyEvent.KEYCODE_F12 || (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT))
				&& event.getAction() == KeyEvent.ACTION_UP) {
			System.out.println("-->点击了：" + "shift + f12");
			
			try {
				canvas.closeConnection();
				canvas.clearAnimation();
				canvas.clearColorFilter();
				canvas.clearFocus();
				canvas.bitmapData = null;
				canvas.sx_cursorBitmap = null;
				canvas.rfbconn = null;
				canvas.decoder = null;
				canvas.pointer = null;
				canvas.keyboard = null;
				canvas.freeRdpApp = null;
				canvas.session = null;
				canvas.pd = null;
				canvas.spicecomm = null;
				canvas = null;
				/* setContentView(null); */
				finish();
				System.gc();
				
			} catch (Exception e) {

			}
			aIsDown = false;
			qIsDown = false;
		} else {
			aIsDown = false;
			qIsDown = false;
		}
		return super.dispatchKeyEvent(event);
	}

	
	long exitTime = 0;

	@Override
	public boolean onKey(View v, int keyCode, KeyEvent evt) {
		Log.v("RemoteCanvas", "----keyCodekeyCode:" + keyCode);
		System.out.println("----keyCodekeyCode:" + keyCode);
		boolean consumed = false;
		if (keyCode == 122 && evt.getAction() == KeyEvent.ACTION_DOWN) {
			if ((System.currentTimeMillis() - exitTime) > 2000) {
				// Toast.makeText(getApplicationContext(), "再按一次退出系统",
				// Toast.LENGTH_SHORT).show();
				exitTime = System.currentTimeMillis();
			} else {
				try {
					canvas.closeConnection();
					canvas.clearAnimation();
					canvas.clearColorFilter();
					canvas.clearFocus();
					canvas.bitmapData = null;
					canvas.sx_cursorBitmap = null;
					canvas.rfbconn = null;
					canvas.decoder = null;
					canvas.pointer = null;
					canvas.keyboard = null;
					canvas.freeRdpApp = null;
					canvas.session = null;
					canvas.pd = null;
					canvas.spicecomm = null;
					canvas = null;
					/* setContentView(null); */
					finish();
					System.gc();

				} catch (Exception e) {

				}
				aIsDown = false;
				qIsDown = false;
				return true;
			}
		}

		if (keyCode == KeyEvent.KEYCODE_MENU) {
			
			  if (evt.getAction() == KeyEvent.ACTION_DOWN) 
			  	return super.onKeyDown(keyCode, evt); 
			  else 
			  	return super.onKeyUp(keyCode,evt);
			 
		}
		else if(keyCode == 0)//软键盘输入
		{
			hideSystemUI(viewcms);
			
		}
		
		try {
			if (evt.getAction() == KeyEvent.ACTION_DOWN
					|| evt.getAction() == KeyEvent.ACTION_MULTIPLE) {
				consumed = inputHandler.onKeyDown(keyCode, evt);
			} else if (evt.getAction() == KeyEvent.ACTION_UP) {
				consumed = inputHandler.onKeyUp(keyCode, evt);
			}
			resetOnScreenKeys(keyCode);
		} catch (NullPointerException e) {
		}

		return consumed;
	}

	public void showPanningState(boolean showLonger) {
		// KE061314
		/*
		 * if (showLonger) { final Toast t = Toast.makeText(this,
		 * inputHandler.getHandlerDescription(), Toast.LENGTH_LONG); TimerTask
		 * tt = new TimerTask () {
		 * 
		 * @Override public void run() { t.show(); try { Thread.sleep(2000); }
		 * catch (InterruptedException e) { } t.show(); }}; new Timer
		 * ().schedule(tt, 2000); t.show(); } else { Toast t =
		 * Toast.makeText(this, inputHandler.getHandlerDescription(),
		 * Toast.LENGTH_SHORT); t.show(); }
		 */
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onTrackballEvent(android.view.MotionEvent)
	 */
	@Override
	public boolean onTrackballEvent(MotionEvent event) {
		try {
			// If we are using the Dpad as arrow keys, don't send the event to
			// the inputHandler.
			if (connection.getUseDpadAsArrows())
				return false;
			return inputHandler.onTrackballEvent(event);
		} catch (NullPointerException e) {

		}
		return super.onTrackballEvent(event);
	}

	
      
	// Send touch events or mouse events like button clicks to be handled.
	 
	@Override
	public boolean onTouchEvent(MotionEvent event) {//继承与activity的函数
		
	  
		
//		X = event.getX();			
		try {
			 inputHandler.onTouchEvent(event);
			/*if(X>1700f)
			{
				   if(CmsControl.functionbar )
					{
												
							pullDownMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {
								
								public void onMenuItemClick(AdapterView<?> parent, View view, int position) {
									// TODO Auto-generated method stub
									
									if(ConstantCategoryMenu.newsMenuTexts[position].equals("软键盘"))
									{
										 if(cmsSoftkeyboard)
										  {
										//cms 初始化一个自定义的Dialog
											PageTask task = new PageTask();
									         task.execute();  
									         cmsSoftkeyboard =false;
										  }
										  else
										  {
									         InputMethodManager im = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); // 关闭软键盘
											 im.hideSoftInputFromWindow(getCurrentFocus().getApplicationWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
											 cmsSoftkeyboard =true;
											 hideSystemUI(viewcms);
										  }
										 
									}
									else if(ConstantCategoryMenu.newsMenuTexts[position].equals("中英切换"))
									{
										
										RemoteKeyboard k = canvas.getKeyboard();
										int key = KeyEvent.KEYCODE_SHIFT_LEFT;//定义发送什么键值										
											BCFactory.getInstance().getBCHaptic()
													.performLongPressHaptic(canvas);
									  
											k.repeatKeyEvent(key, new KeyEvent(MotionEvent.ACTION_DOWN, key));//发送键值
										
										//	resetOnScreenKeys(0);
											
											k.stopRepeatingKeyEvent();//停止发送键值
											
												
									}
									else if(ConstantCategoryMenu.newsMenuTexts[position].equals("切换输入"))
									{
										canvas.getKeyboard().sendMetaKey(MetaKeyBean.keyCtrlShift);//发送组合键值  
									}
									else if(ConstantCategoryMenu.newsMenuTexts[position].equals("退出"))
									{
										canvas.closeConnection();//断开连接
										finish();
									}
									else if(ConstantCategoryMenu.newsMenuTexts[position].equals("切换教学"))
									{
										 boolean isRdp = getPackageName().contains("RDP");
									    if(CmsControl.switchteachingmode)
										{
										 CmsControl.switchteachingmode = false;
										
										 
										 AbstractInputHandler input = new TouchMouseSwipePanInputHandler(RemoteCanvasActivity.this, canvas, isRdp);
										
											     	inputHandler = input;
												    connection.setInputMode(input.getName());
											
													connection.setFollowMouse(true);
													connection.setFollowPan(true);
													
										  Toast.makeText(RemoteCanvasActivity.this, "正常模式", Toast.LENGTH_SHORT).show();
										}
										else
										{
									     CmsControl.switchteachingmode = true;	
									     CmsControl.switchsingledoublesliding = false;
									     
										 AbstractInputHandler input = new TouchMouseDragPanInputHandler(RemoteCanvasActivity.this, canvas, isRdp);
										 
												    inputHandler = input;
												    connection.setInputMode(input.getName());
												
													connection.setFollowMouse(false);
													connection.setFollowPan(false);
												
									     Toast.makeText(RemoteCanvasActivity.this, "教学模式", Toast.LENGTH_SHORT).show();
										}
										showPanningState(true);
										connection.save(database.getWritableDatabase());
										database.close();
									}
									else if(ConstantCategoryMenu.newsMenuTexts[position].equals("切换滑动"))
									{
										if(CmsControl.switchteachingmode == true) //教学模式下无法切换为单指滑动
										{
											
											CmsControl.switchsingledoublesliding = false;
											Toast.makeText(RemoteCanvasActivity.this, "教学模式下无法切换为单指滑动", Toast.LENGTH_SHORT).show();
										}
										else
										{
										if(CmsControl.switchsingledoublesliding == false)//双指滑动模式
										{
											
											CmsControl.switchsingledoublesliding = true;
											
											Toast.makeText(RemoteCanvasActivity.this, "单指滑动模式", Toast.LENGTH_SHORT).show();
										}
										else //单指滑动模式
										{
											
											CmsControl.switchsingledoublesliding = false;
											
											Toast.makeText(RemoteCanvasActivity.this, "双指滑动模式", Toast.LENGTH_SHORT).show();
										}
										}
										
									}
																
								}	
								public void hideMenu() {
									// TODO Auto-generated method stub
								//	Log.v("MainActivity","hidePulldownMenu");
								//	hidePulldownMenu();
								}										
							});
		    				pullDownMenu.show();
					}
					else
					{						
						pullDownMenu.hide(); //弹窗隐藏
					}			
			}*/
			 
			 return true;
		} catch (NullPointerException e) {
		}
		return super.onTouchEvent(event);
	}
	
	//Full-Screen Mode
	   public  void hideSystemUI(View view) {
	        view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
	                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
	                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
	                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
	                | View.SYSTEM_UI_FLAG_FULLSCREEN
	                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);// SYSTEM_UI_FLAG_IMMERSIVE_STICKY   隐藏导栏行 上拉出现后一会儿就消失 
	    }                                                  //SYSTEM_UI_FLAG_IMMERSIVE 隐藏导览行上拉就不会消失
	   
	// Send e.g. mouse events like hover and scroll to be handled.发送如鼠标事件像盘旋和滚动到处理。
	@Override
	public boolean onGenericMotionEvent(MotionEvent event) {
		// Ignore TOOL_TYPE_FINGER events that come from the touchscreen with y
		// == 0.0
		// which cause pointer jumping trouble for some users.
		if (!(event.getY() == 0.0f
				&& event.getSource() == InputDevice.SOURCE_TOUCHSCREEN && event
					.getToolType(0) == MotionEvent.TOOL_TYPE_FINGER)) {
			try {
				return inputHandler.onTouchEvent(event);
			} catch (NullPointerException e) {
			}
		}
		return super.onGenericMotionEvent(event);
	}

	private void selectColorModel() {

		String[] choices = new String[COLORMODEL.values().length];
		int currentSelection = -1;
		for (int i = 0; i < choices.length; i++) {
			COLORMODEL cm = COLORMODEL.values()[i];
			choices[i] = cm.toString();
			if (canvas.isColorModel(cm))
				currentSelection = i;
		}

		final Dialog dialog = new Dialog(this);
		dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
		ListView list = new ListView(this);
		list.setAdapter(new ArrayAdapter<String>(this,
				android.R.layout.simple_list_item_checked, choices));
		list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
		list.setItemChecked(currentSelection, true);
		list.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
					long arg3) {
				dialog.dismiss();
				COLORMODEL cm = COLORMODEL.values()[arg2];
				canvas.setColorModel(cm);
				connection.setColorModel(cm.nameString());
				connection.save(database.getWritableDatabase());
				database.close();
				Toast.makeText(
						RemoteCanvasActivity.this,
						getString(R.string.info_update_color_model_to)
								+ cm.toString(), Toast.LENGTH_SHORT).show();
			}
		});
		dialog.setContentView(list);
		dialog.show();
	}

	long hideZoomAfterMs;
	static final long ZOOM_HIDE_DELAY_MS = 2500;//缩放隐藏延时

	// KE062414 cms
	 HideZoomRunnable hideZoomInstance = new HideZoomRunnable();

	public void stopPanner() {
		panner.stop();
	}

	public void showZoomer(boolean force) {
		// KE062414 cms
		 if (force || zoomer.getVisibility() != View.VISIBLE){ 
			 zoomer.show();
		  hideZoomAfterMs = SystemClock.uptimeMillis() + ZOOM_HIDE_DELAY_MS;
		  canvas.handler.postAtTime(hideZoomInstance, hideZoomAfterMs + 10); 
		  }
		 
	}

	private class HideZoomRunnable implements Runnable {
		public void run() {
			if (SystemClock.uptimeMillis() >= hideZoomAfterMs) {
				zoomer.hide();
			}
		}
	}

	public ConnectionBean getConnection() {
		return connection;
	}

	// Returns whether we are using D-pad/Trackball to send arrow key events.
	public boolean getUseDpadAsArrows() {
		return connection.getUseDpadAsArrows();
	}

	// Returns whether the D-pad should be rotated to accommodate BT keyboards
	// paired with phones.
	public boolean getRotateDpad() {
		return connection.getRotateDpad();
	}

	public float getSensitivity() {
		// TODO: Make this a slider config option.
		return 2.0f;
	}

	public boolean getAccelerationEnabled() {
		// TODO: Make this a config option.
		return true;
	}

	public Database getDatabase() {
		return database;
	}

	public void setDatabase(Database database) {
		this.database = database;
	}

	public RemoteCanvas getCanvas() {
		return canvas;
	}

	public void setCanvas(RemoteCanvas vncCanvas) {
		this.canvas = vncCanvas;
	}

	public Panner getPanner() {
		return panner;
	}

	public void setPanner(Panner panner) {
		this.panner = panner;
	}
	
	
	private class SpiceCloseReceiver extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (action.equals("view.spice.close")) {
				canvas.closeConnection();
				canvas.clearAnimation();
				canvas.clearColorFilter();
				canvas.clearFocus();
				canvas.bitmapData = null;
				canvas.sx_cursorBitmap = null;
				canvas.rfbconn = null;
				canvas.decoder = null;
				canvas.pointer = null;
				canvas.keyboard = null;
				canvas.freeRdpApp = null;
				canvas.session = null;
				canvas.pd = null;
				canvas.spicecomm = null;
				canvas = null;
				finish();
				System.gc();
			}
		}
	}
}
